<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。
//  JCAT 由中国团队开发维护，是一个国际性的项目。
//  正在使用的这个版本是：0.3.2 / SVN信息：$Id: class.JCAT_DBAggregationDocument.php 1250 2009-02-07 04:53:17Z aleechou $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [HTTP下载] http://jcat.JeCat.cn/download
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.cn/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.cn/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/






/**
 * What's this Class ?
 *
 * @author		alee
 * @access		public
 */
class JCAT_DBAggregationDocument extends JCAT_Document implements JCAT_IDBDocument, JCAT_IPaginal
{
	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$sName				string			文档名称
	 * @param	$sChildDocClass=null	string			子文档类名
	 * @return	void
	 */
	public function JCAT_DBAggregationDocument( $sName, $sChildDocClass=null )
	{
		// 子文档原型
		if( $sMsg=JCAT_Language::SentenceEx('参数 $sChildDocClass 必须为 JCAT_DBDocument 派生类类名。','JCAT',null) and !JCAT_Global::IsKindOf($sChildDocClass,'JCAT_DBDocument') )
		{
			throw new JCAT_Exception( $sMsg, __macro_exception_code__ ) ;
		}

		if($sChildDocClass)
		{
			JCAT_ASSERT::ASSERT_ISCLASS($sChildDocClass,array('JCAT_IDocument'));
			$this->SetChildDocumentPrototype(new $sChildDocClass()) ;
		}

		$this->JCAT_Document($sName) ;
	}
	
	
	/**
	 * 文档是否存在
	 * 
	 * @access	public
	 * @param	$bRequery=false		bool	对于高级文档（如数据库文档），查询 文档是否存在 会存在一定性能代价 ，该参数允许缓存查询结果
	 * @return	bool
	 */
	public function IsExists( $bRequery=false )
	{
		return true ;
	}
	
	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	bool
	 */
	public function Load()
	{
		$aRecordSet = $this->QueryForRecordset() ;
		if( $aRecordSet===null )
		{
			return false ;
		}

		// 从记录集中载入数据
		$nIdx = 0 ;
		while( $aRecordSet->GetRow() )
		{
			$aChildDoc = clone $this->aChildDocPrototype ;
					
			JCAT_ASSERT::ASSERT_( $aChildDoc->LoadDataFromRecordSet($aRecordSet)
				, JCAT_Language::SentenceEx('子文档载入失败。','JCAT'))  ;

			// 子文档名称
			$sId = $aChildDoc->GetPrimaryKeyValue() ;
			$sChildDocumentName = $this->aChildDocPrototype->GetName() . '_' . ($sId?$sId:$nIdx) ;
			$aChildDoc->SetName( $sChildDocumentName ) ;
			
			// 加入文档
			$this->AddDocument($aChildDoc,$sChildDocumentName) ;
			
			$aRecordSet->Fetch() ;
			$nIdx ++ ;
		}

		return true ;
	}

	
	/**
	 * 设置关键词
	 *
	 * @access	public
	 * @param	$sKeywords			string
	 * @return	void
	 */
	public function SetKeywords($sKeywords,$arrClmNames)
	{
		$aPrototype = $this->GetChildDocumentPrototype() ;
		$aWhere = $aPrototype->GetSubSQLWhere() ;
		$aFactory = $aWhere->GetFactory() ;
		$aGroup = $aWhere->AddGroup(false) ;

		foreach ($arrClmNames as $sClmName)
		{
			$aCondition = $aFactory->CreateSubSQLCondition(
								$aGroup
								, $aFactory->CreateColumn($sClmName)
								, "%{$sKeywords}%"
								, 'LIKE' ) ;
			$aGroup->AddCondition($aCondition) ;
		}
	}
	
	/**
	 * 根据 主键键值 取得子文档
	 *
	 * @access	public
	 * @param	$PrimaryKeyValue
	 * @return	JCAT_DBDocument
	 */
	public function GetDocumentByPrimaryKeyValue( $PrimaryKeyValue )
	{
		$sName = $this->aChildDocPrototype->GetName() . '_' . $PrimaryKeyValue ;
		return $this->GetDocument($sName) ;
	}
	
	/**
	 * 添加一项查询条件
	 *
	 * @access	public
	 * @param	$sColumnName		string			字段名
	 * @param	$Value				string,int		值
	 * @param	$sOperator='='		string			操作符号
	 * @param	$RightB=null			string,int		用于三目运算的 右边第二个参数
	 * @return	JCAT_DBSubSQLCondition
	 */
	public function AddCondition($sColumnName,$Value,$sOperator='=', $RightB=null)
	{
		$aPrototype = $this->GetChildDocumentPrototype() ;
		JCAT_ASSERT::ASSERT_INSTANCE($aPrototype,'JCAT_DBDocument',JCAT_Language::SentenceEx('文档(%s)尚未设置 子文档原型。','JCAT',null,$this->GetName()));
		
		$aSubSQLWhere = $aPrototype->GetSubSQLWhere() ;
		$aFactory = $aSubSQLWhere->GetFactory() ;

		$aColumn = $aFactory->CreateColumn($sColumnName) ;
		JCAT_ASSERT::ASSERT_INSTANCE($aColumn,'JCAT_DBColumn'
					, JCAT_Language::SentenceEx('传入的参数 $sColumnName(%s) 不是一个有效格式的字段名称。','JCAT',null,$sColumnName)) ;
	
		return $aSubSQLWhere->AddCondition($aColumn,$Value,$sOperator,$RightB) ;
	}
	
	/**
	 * 查询并返回记录集
	 *
	 * @access	public
	 * @return	JCAT_DBRecordSet
	 */
	public function QueryForRecordset()
	{
		JCAT_ASSERT::ASSERT_NOTNULL($this->aChildDocPrototype
				, JCAT_Language::SentenceEx('载入聚合数据库文档(%s)时出错，请先调用 SetChildDocumentPrototype() 函数或在 JCAT_DBAggregationDocument 的构造函数中传入原型对象的类名。','JCAT',null,$this->GetName()));

		$aSelect = $this->aChildDocPrototype->MakeSQLSelect() ;		
		$aDB = $this->aChildDocPrototype->GetDB() ;
		
		// 创建记录集对象
		$aRecordSet = $aDB->GetFactory()->CreateRecordSet($aDB->GetConnect()) ;
		JCAT_ASSERT::ASSERT_INSTANCE($aRecordSet,'JCAT_DBRecordSet') ;
		
		// 查询所有符合条件的记录
		if( !$this->OnQuery($aSelect,$aRecordSet) )
		{
			return null ;
		}
	
		// 总页数
		$this->nTotalRecordCount = $aRecordSet->GetCount() ;
		
		// 通过页码条 确定记录起止位置
		$aPagination = $this->GetPagination() ;
		if($aPagination and $this->GetPageCount())
		{
			// 设置 页码条
			$aPagination->SetPageCount($this->GetPageCount()) ;
			
			$nPageNum = $aPagination->GetCurrentPage() ;
			$this->SetPageNumber($nPageNum) ;
		}

		// 查询本页内容
		$nStart = $this->GetRecordCountPerPage() * ($this->GetPageNumber()-1) ;
		$aSelect->SetLimit($this->GetRecordCountPerPage(),$nStart) ;
		
		// 查询
		if( !$this->OnQuery($aSelect,$aRecordSet) )
		{
			return null ;
		}
		
		return $aRecordSet ;
	}

	/**
	 * 执行实际的查询操作， 可以重載该方法，以便实现更高级的文档查询操作
	 * 
	 * @access	public
	 * @param	$aSelect		JCAT_DBSQLSelect		what's this
	 * @param	$aRecordSet		JCAT_DBRecordSet		what's this
	 * @return	bool
	 */
	public function OnQuery(JCAT_DBSQLSelect $aSelect,JCAT_DBRecordSet $aRecordSet)
	{
		return $aRecordSet->Query($aSelect) ;
	}

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	JCAT_DB
	 */
	public function GetDB() 
	{
		JCAT_ASSERT::ASSERT_NOTNULL($this->aChildDocPrototype
				, JCAT_Language::SentenceEx('载入聚合数据库文档(%s)时出错，请先调用 SetChildDocumentPrototype() 函数或在 JCAT_DBAggregationDocument 的构造函数中传入原型对象的类名。','JCAT',null,$this->GetName()));
				
		return $this->aChildDocPrototype->GetDB() ;
	}
	
	/**
	 * 设置 每页记录数
	 *
	 * @access	public
	 * @param	$nRecordCount	int		What's this Parameter ?
	 * @return	old_value
	 */
	public function SetRecordCountPerPage( $nRecordCount )
	{
		JCAT_ASSERT::ASSERT_($nRecordCount>=0,JCAT_Language::SentenceEx('参数 $nRecordCount 必须大于等于0，传入数值为：“%d”','JCAT',null,$nRecordCount)) ;

		$old_value = $this->nRecordsPerPage ;
		$this->nRecordsPerPage = $nRecordCount ;
		return $old_value ;
	}
	
	
	/**
	 * 返回 每页记录数
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetRecordCountPerPage()
	{
		return $this->nRecordsPerPage ;
	}
	
	/**
	 * 返回 本页记录数
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetRecordCount()
	{
		return $this->GetDocumentCount() ;
	}

	/**
	 * 返回 所有符合条件的记录数
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetTotalRecordCount()
	{
		return $this->nTotalRecordCount ;
	}
	
	/**
	 * 取回总页数
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetPageCount()
	{
		$nCountPerPage = $this->GetRecordCountPerPage() ;
		return $nCountPerPage? intval(ceil($this->GetTotalRecordCount()/$nCountPerPage)): 0 ;
	}
	
	/**
	 * 设置当前页数
	 *
	 * @access	public
	 * @return	void
	 */
	public function SetPageNumber( $nPageNum )
	{
		JCAT_ASSERT::ASSERT_INT($nPageNum) ;
		$this->nPageNumber = $nPageNum ;
	}
	
	/**
	 * 取回当前页数
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetPageNumber()
	{
		return $this->nPageNumber ;
	}
	
	
	

	public function Save( $bIgnoreChanged=false )
	{ JCAT_ASSERT::ASSERT_(0,JCAT_Language::SentenceEx('此文档为聚合文档，请对单项文档进行操作。','JCAT',null)) ; }
	
	public function Delete()
	{ JCAT_ASSERT::ASSERT_(0,JCAT_Language::SentenceEx('此文档为聚合文档，请对单项文档进行操作。','JCAT',null)) ; }
	
	public function Create()
	{ JCAT_ASSERT::ASSERT_(0,JCAT_Language::SentenceEx('此文档为聚合文档，请对单项文档进行操作。','JCAT',null)) ; }

	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$aPrototype		JCAT_IDocument		what's this
	 * @return	old_value
	 */
	public function SetChildDocumentPrototype(JCAT_IDocument $aPrototype)
	{
		$old_value = $this->aChildDocPrototype ;
		$this->aChildDocPrototype = $aPrototype ;
		return $old_value ;
	}
	
	/**
	 * 返回子文档原型对象
	 *
	 * @access	public
	 * @return	JCAT_DBDocument
	 */
	public function GetChildDocumentPrototype()
	{
		return $this->aChildDocPrototype ;
	}
	
	
	/**
	 * 设置页码对象
	 *
	 * @access	public
	 * @param	$aPagination	JCAT_IPagination
	 * @return	JCAT_IPagination
	 */
	public function SetPagination(JCAT_IPagination $aPagination)
	{
		$old_value = $this->aPagination ;
		$this->aPagination = $aPagination ;
		return $old_value ;
	}
	
	/**
	 * 返回页码对象
	 *
	 * @access	public
	 * @return	JCAT_IPagination
	 */
	public function GetPagination()
	{
		return $this->aPagination ;
	}
	
	/**
	 * 设置 Order By 字段
	 *
	 * @access	public
	 * @param	$sColumnName		string
	 * @param	$bDesc=false		bool
	 * @return	void
	 */
	public function SetOrderBy($sColumnName,$bDesc=false)
	{
		$aPrototype = $this->GetChildDocumentPrototype() ;
		$aDB = $aPrototype->GetDB() ;
		$aFactory = $aDB->GetFactory() ;
		
		$aColumn = $aFactory->CreateColumn($sColumnName) ;
		$aOrderBy = $aFactory->CreateSubSQLOrder() ;
		$aOrderBy->AddOrder($aColumn,$bDesc);
		
		$aPrototype->SetSubSQLOrder($aOrderBy) ;
	}
	
	// 属性 ///////////////////////////////////////////////////////////////////////////////


	private $nRecordsPerPage = 30 ;
	
	private $nTotalRecordCount = 0 ;
	
	private $nPageNumber = 1 ;

	private $aChildDocPrototype ;
	
	/**
	 * 页码
	 * 
	 * @access	private
	 * @var		JCAT_IPagination
	 */
	private $aPagination ;
		
}



?>